﻿#define DEBUG

using System;
using System.Collections.Generic;
using System.Text;

using System.Runtime.InteropServices;
using System.Collections;
using System.Drawing;

using SuperMapLib;

namespace JR_RouteAlarm
{
    class Route : IRoute
    {
        /*定数*/
        public const string FLD_FEATURE_CD = Utility.FEATURE;
        public const string FLD_DAIBUN_CD = Utility.DAIBUN;
        public const string FLD_TSUUSHO_CD = Utility.TSUUSHO;
        public const string FLD_LABEL_TEXT = Utility.LABEL_TEXT;

        private soDatasets objDSs = null;

        public Route(soDatasets objDSs)
        {
            this.objDSs = objDSs;
        }

        #region IRoute メンバ

        private string feature = String.Empty;
        public string Feature
        {
            get
            {
                return feature;
            }
            set
            {
                feature = value;
            }
        }

        private string daibun = String.Empty;
        public string Daibun
        {
            get
            {
                return daibun;
            }
            set
            {
                daibun = value;
            }
        }

        private string tsuusho = String.Empty;
        public string Tsuusho
        {
            get
            {
                return tsuusho;
            }
            set
            {
                tsuusho = value;
            }
        }

        public void MakeBufferForRoute(soDatasetVector objVector, soRecordset objRS)
        {
            soRecordset objSubRs = null;

            feature = objRS.GetFieldValue(FLD_FEATURE_CD).ToString();
            daibun = objRS.GetFieldValue(FLD_DAIBUN_CD).ToString();
            tsuusho = objRS.GetFieldValue(FLD_TSUUSHO_CD).ToString();

            objSubRs = objVector.Query(
                FLD_FEATURE_CD + " = '" + feature + "' and " +
                FLD_DAIBUN_CD + " = '" + daibun + "' and " +
                FLD_TSUUSHO_CD + " = '" + tsuusho + "'",
                true, null, "");

            if (objSubRs != null && objSubRs.RecordCount > 0)
            {
                if (!objSubRs.IsBOF())
                {
                    objSubRs.MoveFirst();
                }

                soGeoLine objFullRoute = null;
                soGeoLine objLineTmp = null;
                for (; !objSubRs.IsEOF(); objSubRs.MoveNext())
                {
                    objLineTmp = objSubRs.GetGeometry() as soGeoLine;
                    if (objFullRoute == null)
                    {
                        objFullRoute = objLineTmp;
                        continue;
                    }
                    if (!objFullRoute.Joint(objLineTmp))
                    {
                        Marshal.ReleaseComObject(objLineTmp);
                        objLineTmp = null;
                        objSubRs.Close();
                        Marshal.ReleaseComObject(objSubRs);
                        objSubRs = null;
                        Marshal.ReleaseComObject(objFullRoute);
                        objFullRoute = null;

                        throw new Exception("Joint line failed!");
                    }
                }
                objSubRs.Close();

                MakeBufferForPart(objFullRoute);

                Marshal.ReleaseComObject(objLineTmp);
                objLineTmp = null;
                Marshal.ReleaseComObject(objSubRs);
                objSubRs = null;
                Marshal.ReleaseComObject(objFullRoute);
                objFullRoute = null;
            }
        }

        private void MakeBufferForPart(soGeoLine objFullRoute)
        {
            soGeoLine[] objLinesDividing = null;
            soPoints tmpPointsDividing = null;
            soGeoRegion objBuffer = null;
            soGeoLine objLineTmp = null;

            objLinesDividing = new soGeoLine[3];
            objLinesDividing[0] = new soGeoLine();
            objLinesDividing[1] = new soGeoLine();
            objLinesDividing[2] = new soGeoLine();
            objLineTmp = new soGeoLine();
            //tmpPointsDividing = new Examples(objDSs).FindDividingPoints(objDSs, objFullRoute);
            tmpPointsDividing = FindDividingPoints(objDSs, objFullRoute);
            objFullRoute.Split(tmpPointsDividing[1], objLinesDividing[0], objLineTmp);
            objLineTmp.Split(tmpPointsDividing[2], objLinesDividing[1], objLinesDividing[2]);
            
            objBuffer = objLinesDividing[0].SpatialOperator.Buffer2(
                Utility.BUFFER_ALARM_DISTANCE_2, Utility.BUFFER_ALARM_DISTANCE_2, 0);
            Utility.routeLnWithBfr[objLinesDividing[0]] = objBuffer;
            objBuffer = objLinesDividing[1].SpatialOperator.Buffer2(
                Utility.BUFFER_ALARM_DISTANCE_2, Utility.BUFFER_ALARM_DISTANCE_2, 0);
            Utility.routeLnWithBfr[new object[2] { objLinesDividing[0], new string[3] {feature, daibun, tsuusho} }] = objBuffer;
            objBuffer = objLinesDividing[2].SpatialOperator.Buffer2(
                Utility.BUFFER_ALARM_DISTANCE_2, Utility.BUFFER_ALARM_DISTANCE_2, 0);
            Utility.routeLnWithBfr[objLinesDividing[2]] = objBuffer;

            Marshal.ReleaseComObject(objLineTmp);
            objLineTmp = null;
            Marshal.ReleaseComObject(tmpPointsDividing);
            tmpPointsDividing = null;
            //Marshal.ReleaseComObject(objLinesDividing[0]);
            //objLinesDividing[0] = null;
            //Marshal.ReleaseComObject(objLinesDividing[1]);
            //objLinesDividing[1] = null;
            //Marshal.ReleaseComObject(objLinesDividing[2]);
            //objLinesDividing[2] = null;
            //Marshal.ReleaseComObject(objBuffer);
            //objBuffer = null;
        }

        private soPoints FindDividingPoints(soDatasets objDSs, soGeoLine objLine)
        {
            soDataset objDSPoint = null;
            soDatasetVector objDatasetV = null;
            soRecordset objRS = null;
            soGeoPoint objPointTmp = null;
            soGeoPoint[] objPointsCross = null;
            soGeoRegion[] objRegions = null;
            soPoints tmpPoints = null;

            objRegions = new soGeoRegion[Utility.MAX_ROUTE_NUM];
            objPointsCross = GetCrossingPoints(objLine, ref objRegions);

            objDSPoint = objDSs["キロ標_大宮"];
            objDatasetV = objDSPoint as soDatasetVector;
            objRS = objDatasetV.Query("-1 < 0", true, null, "");
            if (objRS != null && objRS.RecordCount > 0)
            {
                if (objRS.IsEOF())
                {
                    objRS.MoveFirst();
                }

                soGeometry objMetry = null;
                for (; !objRS.IsEOF(); objRS.MoveNext())
                { 
                    objMetry = objRS.GetGeometry();
                    if (!objLine.SpatialRelation.Contains(objMetry))
                    {
                        objRS.Delete();
                    }
                }
                objRS.Close();

                tmpPoints = new soPoints();
                for (int i = 0; i < Utility.MAX_CROSSING_NUM; i++)
                {
                    if (objPointsCross[i] == null)
                    {
                        break;
                    }
                    objRS = objDatasetV.QueryByDistance(
                        objPointsCross[i] as soGeometry, Utility.KIROTEI_DISTANCE, "");
                    if (objRS != null && objRS.RecordCount > 0)
                    {
                        objRS.MoveFirst();
                        for (; !objRS.IsEOF(); objRS.MoveNext())
                        {
#if DEBUG
                            objPointTmp = objRS.GetGeometry() as soGeoPoint;
                            Console.WriteLine("x={0}, y={1}, {2}", objPointTmp.x, objPointTmp.y, i);
#endif
                            for (int j = 0; j < objRegions.Length; j++)
                            {
                                if (objRegions[j] == null)
                                {
                                    break;
                                }
                                if (objPointTmp.SpatialRelation.Within(objRegions[j] as soGeometry))
                                {
#if RELEASE
                                    objPointTmp = objRS.GetGeometry() as soGeoPoint;
#endif
                                    //objPointsDividing[i] = objPointTmp;
                                    tmpPoints.Add2(objPointTmp.x, objPointTmp.y);
                                    continue;
                                }
                            }
                        }
                        objRS.Close();
                    }
                }
                objDatasetV.Close();
                objDatasetV.ClearRecordsets();
            }

            Marshal.ReleaseComObject(objPointTmp);
            objPointTmp = null;
            Marshal.ReleaseComObject(objDatasetV);
            objDatasetV = null;
            Marshal.ReleaseComObject(objRS);
            objRS = null;
            Marshal.ReleaseComObject(objDSPoint);
            objDSPoint = null;

            return tmpPoints;
        }

        private soGeoPoint[] GetCrossingPoints(soGeoLine objLine, ref soGeoRegion[] objRegions )
        {
            soDataset objDSRegion = null;
            soDatasetVector objDatasetV = null;
            soRecordset objRS = null;
            soPoints tmpPoints = null;
            soGeoPoint[] objPoints = null;
            soGeoRegion objRegion = null;
            int regionIdx = 0;
            int pointIdx = 0;

            objPoints = new soGeoPoint[Utility.MAX_CROSSING_NUM];
            for (int i = 1; i <= objDSs.Count; i++)
            {
                if (objDSs[i].GetDatasetInfo().Name.StartsWith(Utility.BUFFER_TITLE_1000, true, null))
                {
                    objDSRegion = objDSs[i];
                    objDatasetV = objDSRegion as soDatasetVector;
                    objRS = objDatasetV.Query("-1 < 0", true, null, "");
                    if (objRS != null && objRS.RecordCount > 0)
                    {
                        objRS.MoveFirst();
                    }
                    objRegion = objRS.GetGeometry() as soGeoRegion;
                    tmpPoints = objLine.GetCrossings(objRegion as soGeometry);
                    objRS.Close();
                    objDatasetV.Close();
                    objDatasetV.ClearRecordsets();
                    if (tmpPoints == null || tmpPoints.Count == 0)
                    {
                        continue;
                    }
                    objRegions[regionIdx++] = objRegion;

                    int j = 0;
                    for (; j < tmpPoints.Count; j++)
                    {
                        objPoints[pointIdx + j] = new soGeoPoint();
                        objPoints[pointIdx + j].x = tmpPoints[j + 1].x;
                        objPoints[pointIdx + j].y = tmpPoints[j + 1].y;
                    }
                    pointIdx += j;
                }
            }

            if (tmpPoints != null)
            {
                Marshal.ReleaseComObject(tmpPoints);
                tmpPoints = null;
            }
            Marshal.ReleaseComObject(objDSRegion);
            objDSRegion = null;
            Marshal.ReleaseComObject(objRS);
            objRS = null;
            Marshal.ReleaseComObject(objDatasetV);
            objDatasetV = null;

            return objPoints;
        }

        #endregion
    }
}
